package com.zhan.rkforum.controller.filter;


import org.apache.commons.lang3.CharUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * 敏感词字典树
 *
 * @author wujiazhan
 * @date 2021/07/01
 */
@SuppressWarnings("all")
@Component
public class SensitiveFilter {

    private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);

    /**
     * 节点内部类
     *
     * @author wujiazhan
     * @date 2021/07/01
     */
    class Node{
        boolean isSensitive;
        Map<Character, Node> next;
        public Node(char ch){
            this(false,ch);
        }

        public Node(boolean isSensitive, Character ch){
            this.isSensitive = isSensitive;
            this.next = new HashMap<>();
        }
        public Node(){
            this(false,null);
        }
    }

    private Node root = new Node();

    @PostConstruct
    private void init() {
        try(
                InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
        ){
            String word = "";
            while ((word = br.readLine()) != null){
                this.add(word);
            }
        }catch (IOException e) {
            logger.error("读取敏感词文本失败：" + e.getMessage());
        }
    }

    /**
     * 添加敏感词到字典树
     *
     * @param word 词
     */
    private void add(String word){
        Node cur = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            Node node = cur.next.get(c);
            if(node == null){
                cur.next.put(c, new Node());
            }
            cur = cur.next.get(c);
        }
        cur.isSensitive = true;

    }

    private boolean isContains(String string){
        Node cur = root;
        for (int i = 0; i < string.length(); i++) {
            char c = string.charAt(i);
            if(isSymbol(c)){
                continue;
            }
            Node node = cur.next.get(c);
            if(node == null){
                return false;
            }
            cur = cur.next.get(c);
        }
        return cur.isSensitive;
    }

    public String filter(String string){
        Node cur = root;
        StringBuilder sb = new StringBuilder();
        int left = 0;
        int right = 0;
        while (left < string.length()) {
            String sub = string.substring(left,right+1);
            if(isContains(sub)){
                for (int i = 0; i < sub.length(); i++) {
                    sb.append("*");
                }
                string = string.replace(sub,sb.toString());
                left = right + 1;
            }
            right ++;
            if(right == string.length()){
                left ++;
                right = left;
            }
        }
        return string;
    }

    /**
     * 是否是特殊字符（非中文的特殊字符，例如：θ）
     *
     * @param c c
     * @return boolean
     */
    private boolean isSymbol(char c){
        // 0x2E80 ~ 0x9FFF是东亚字符范围
        return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
    }
}
